home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / NDK / NDK_3.5 / Examples / Printer / HP_DeskJet_CMYK / render.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-30  |  14.3 KB  |  588 lines

  1. /*
  2.  * $Id: render.c 44.7 1999/09/22 19:48:18 olsen Exp olsen $
  3.  *
  4.  * :ts=4
  5.  *
  6.  * COPYRIGHT:
  7.  *
  8.  *   Unless otherwise noted, all files are Copyright (c) 1999 Amiga, Inc.
  9.  *   All rights reserved.
  10.  *
  11.  * DISCLAIMER:
  12.  *
  13.  *   This software is provided "as is". No representations or warranties
  14.  *   are made with respect to the accuracy, reliability, performance,
  15.  *   currentness, or operation of this software, and all use is at your
  16.  *   own risk. Neither Amiga nor the authors assume any responsibility
  17.  *   or liability whatsoever with respect to your use of this software.
  18.  *
  19.  */
  20.  
  21. #include "global.h"
  22.  
  23. /****************************************************************************/
  24.  
  25. #include "config.h"
  26.  
  27. /****************************************************************************/
  28.  
  29. /* These are for dithering with error dispersion; we reserve space for up to
  30.  * four colour components. For the monochrome driver, only one will
  31.  * be used, though.
  32.  */
  33. STATIC DITHERDATA_T * dither_data[PCMBLACK-PCMYELLOW+1];
  34.  
  35. /****************************************************************************/
  36.  
  37. /* These buffers are for transferring the raster data to the printer. */
  38. STATIC UBYTE * print_buffers[2 * (PCMBLACK-PCMYELLOW+1)];
  39. STATIC LONG current_print_buffer;
  40. STATIC LONG num_print_buffers;
  41.  
  42. /****************************************************************************/
  43.  
  44. /* This buffer will be used for colour correction. */
  45. union colorEntry * colour_correction_buffer;
  46.  
  47. /****************************************************************************/
  48.  
  49. /* Number of bytes in a row of raster data. */
  50. STATIC LONG num_bytes_per_row;
  51.  
  52. /****************************************************************************/
  53.  
  54. /* Source buffers for doing data compression; must be large enough to
  55.  * hold a single line of bitmap graphics. We reserve space for up to
  56.  * four colour components. For the monochrome driver, only one will
  57.  * be used, though.
  58.  */
  59. STATIC UBYTE * render_buffer[PCMBLACK-PCMYELLOW+1];
  60.  
  61. /****************************************************************************/
  62.  
  63. /* For composing the printer commands. */
  64. #define COMMAND_BUFFER_SIZE 256
  65.  
  66. STATIC UBYTE command_buffers[2][COMMAND_BUFFER_SIZE];
  67. STATIC LONG current_command_buffer;
  68.  
  69. /****************************************************************************/
  70.  
  71. /* Gamma correction table to use. */
  72. STATIC UBYTE * gamma_table;
  73.  
  74. /****************************************************************************/
  75.  
  76. /* Send a command to the printer; this uses one of two
  77.  * buffers, to take advantage of double-buffer I/O.
  78.  */
  79. STATIC LONG
  80. SendPrinterCommand(UBYTE * fmt,...)
  81. {
  82.     UBYTE * buffer = command_buffers[current_command_buffer];
  83.     va_list varArgs;
  84.     LONG error;
  85.  
  86.     va_start(varArgs,fmt);
  87.     VSPrintf(buffer,fmt,varArgs);
  88.     va_end(varArgs);
  89.  
  90.     error = (*PWrite)(buffer,strlen(buffer));
  91.  
  92.     current_command_buffer = (1 - current_command_buffer);
  93.  
  94.     return(error);
  95. }
  96.  
  97. /****************************************************************************/
  98.  
  99. /* This routine makes a local copy of the colour data and applies
  100.  * gamma correction to it.
  101.  */
  102. STATIC VOID
  103. CorrectColours(struct PrtInfo * pi,UBYTE * gamma_table,union colorEntry * colour_buffer)
  104. {
  105.     LONG x,c;
  106.  
  107.     /* Make a copy of the colour data. */
  108.     memcpy(colour_buffer,pi->pi_ColorInt,sizeof(*colour_buffer) * pi->pi_width);
  109.  
  110.     for(x = 0 ; x < pi->pi_width ; x++)
  111.     {
  112.         for(c = PCMYELLOW ; c <= PCMBLACK ; c++)
  113.             colour_buffer->colorByte[c] = gamma_table[colour_buffer->colorByte[c]];
  114.  
  115.         colour_buffer++;
  116.     }
  117. }
  118.  
  119. /****************************************************************************/
  120.  
  121. /* Clear each CMY pixel if there is a K pixel which
  122.  * would cover it.
  123.  */
  124. STATIC VOID
  125. ClearColour(UBYTE * render_buffer[],LONG num_bytes_per_row)
  126. {
  127.     UBYTE k;
  128.     LONG i,j;
  129.  
  130.     for(i = 0 ; i < num_bytes_per_row ; i++)
  131.     {
  132.         k = ~render_buffer[PCMBLACK][i];
  133.  
  134.         for(j = PCMYELLOW ; j <= PCMCYAN ; j++)
  135.             render_buffer[j][i] &= k;
  136.     }
  137. }
  138.  
  139. /****************************************************************************/
  140.  
  141. LONG __stdargs __saveds
  142. Render(LONG ct,LONG x,LONG y,LONG status)
  143. {
  144.     LONG err = PDERR_NOERR;
  145.     LONG i;
  146.     int shingling;
  147.     int depletion;
  148.     int threshold;
  149.     int num_components;
  150.     struct PrtInfo * pi;
  151.     union colorEntry * colour_buffer;
  152.  
  153.     switch(status)
  154.     {
  155.         /* Master Initialization */
  156.         case 0 :
  157.             /*    ct    - pointer to IODRPReq structure.
  158.              *    x    - width of printed picture in pixels.
  159.              *    y    - height of printed picture in pixels.
  160.              */
  161.             num_bytes_per_row = (x + 7) / 8;
  162.  
  163.             /* Allocate memory for the buffer we will render into and
  164.              * whose contents will be compressed before they are
  165.              * transferred to the printer.
  166.              */
  167.             if(CONFIG_SUPPORTS_COLOR && PD->pd_Preferences.PrintShade == SHADE_COLOR)
  168.             {
  169.                 for(i = PCMYELLOW ; i <= PCMBLACK ; i++)
  170.                 {
  171.                     render_buffer[i] = AllocVec(num_bytes_per_row,MEMF_ANY|MEMF_PUBLIC);
  172.                     if(render_buffer[i] == NULL)
  173.                     {
  174.                         err = PDERR_BUFFERMEMORY; /* not enough memory */
  175.                         break;
  176.                     }
  177.                 }
  178.             }
  179.             else
  180.             {
  181.                 render_buffer[PCMBLACK] = AllocVec(num_bytes_per_row,MEMF_ANY|MEMF_PUBLIC);
  182.                 if(render_buffer[PCMBLACK] == NULL)
  183.                 {
  184.                     err = PDERR_BUFFERMEMORY; /* not enough memory */
  185.                     break;
  186.                 }
  187.             }
  188.  
  189.             if(err != PDERR_NOERR)
  190.                 break;
  191.  
  192.             /* Number of buffers to allocate for printing; we need
  193.              * twice as many as there are colour components to work
  194.              * with (for double-buffering).
  195.              */
  196.             num_components = (CONFIG_SUPPORTS_COLOR && PD->pd_Preferences.PrintShade == SHADE_COLOR) ? 4 : 1;
  197.             num_print_buffers = 2 * num_components;
  198.  
  199.             /* Now allocate the data transfer buffers. */
  200.             for(i = 0 ; i < num_print_buffers ; i++)
  201.             {
  202.                 print_buffers[i] = AllocVec(num_bytes_per_row,MEMF_ANY|MEMF_PUBLIC);
  203.                 if(print_buffers[i] == NULL)
  204.                 {
  205.                     err = PDERR_BUFFERMEMORY; /* not enough memory */
  206.                     break;
  207.                 }
  208.             }
  209.  
  210.             if(err != PDERR_NOERR)
  211.                 break;
  212.  
  213.             /* If we are going to use the Floyd-Steinberg filter
  214.              * we'd better set up the line buffers.
  215.              */
  216.             if((PD->pd_Preferences.PrintFlags & DITHERING_MASK) == FLOYD_DITHERING)
  217.             {
  218.                 if(CONFIG_SUPPORTS_COLOR && PD->pd_Preferences.PrintShade == SHADE_COLOR)
  219.                 {
  220.                     for(i = PCMYELLOW ; i <= PCMBLACK ; i++)
  221.                     {
  222.                         dither_data[i] = CreateDitherData(x,2,1);
  223.                     /*    dither_data[i] = CreateDitherData(x,3,2);    */
  224.                         if(dither_data[i] == NULL)
  225.                         {
  226.                             err = PDERR_BUFFERMEMORY; /* not enough memory */
  227.                             break;
  228.                         }
  229.                     }
  230.                 }
  231.                 else
  232.                 {
  233.                     dither_data[PCMBLACK] = CreateDitherData(x,2,1);
  234.                 /*    dither_data[PCMBLACK] = CreateDitherData(x,3,2);    */
  235.                     if(dither_data[PCMBLACK] == NULL)
  236.                     {
  237.                         err = PDERR_BUFFERMEMORY; /* not enough memory */
  238.                         break;
  239.                     }
  240.                 }
  241.  
  242.                 if(err != PDERR_NOERR)
  243.                     break;
  244.             }
  245.  
  246.             /* Set shingling and depletion according
  247.              * to density:
  248.              *
  249.              * 1-3: No  depletion, no  shingling
  250.              *   4: 25% depletion, no  shingling
  251.              *   5: 25% depletion, 50% shingling
  252.              *   6: 25% depletion, 25% shingling
  253.              *   7: No  depletion, 25% shingling
  254.              *
  255.              * Case 7 is meant for transparencies.
  256.              *
  257.              * Depletion is ignored in B&W mode
  258.              */
  259.             switch(PD->pd_Preferences.PrintDensity)
  260.             {
  261.                 /* Standard */
  262.                 case 4:
  263.                     depletion = 2;
  264.                     shingling = 0;
  265.                     break;
  266.  
  267.                 /* Normal */
  268.                 case 5:
  269.                     depletion = 2;
  270.                     shingling = 1;
  271.                     break;
  272.  
  273.                 /* Best */
  274.                 case 6:
  275.                     depletion = 2;
  276.                     shingling = 2;
  277.                     break;
  278.  
  279.                 /* Best for transparencies */
  280.                 case 7:
  281.                     depletion = 1;
  282.                     shingling = 2;
  283.                     break;
  284.  
  285.                 /* Anything else */
  286.                 default:
  287.                     depletion = 1;
  288.                     shingling = 0;
  289.                     break;
  290.             }
  291.  
  292.             /* Now pick the gamma correction table to use. */
  293.             threshold = PD->pd_Preferences.PrintThreshold;
  294.             if(threshold < 1)
  295.                 threshold = 1;
  296.             else if (threshold > 15)
  297.                 threshold = 15;
  298.  
  299.             /* Threshold value 1 stands for uncorrected
  300.              * data. It maps the input data 1:1 to the
  301.              * output. To save time and memory, we won't
  302.              * bother to deal with this special case.
  303.              */
  304.             if(CONFIG_SUPPORTS_COLOR && threshold > 1)
  305.             {
  306.                 gamma_table = GammaTables[threshold - 2];
  307.  
  308.                 /* This buffer will be used for colour correction later. */
  309.                 colour_correction_buffer = AllocVec(sizeof(*colour_correction_buffer) * x,MEMF_ANY|MEMF_PUBLIC);
  310.                 if(colour_correction_buffer == NULL)
  311.                 {
  312.                     err = PDERR_BUFFERMEMORY; /* not enough memory */
  313.                     break;
  314.                 }
  315.             }
  316.             else
  317.             {
  318.                 /* Don't perform colour correction. */
  319.                 gamma_table = NULL;
  320.                 colour_correction_buffer = NULL;
  321.             }
  322.  
  323.             if(CONFIG_SUPPORTS_COLOR)
  324.             {
  325.                 err = SendPrinterCommand(
  326.                     "\033*o"
  327.                     "%ldq"            /* shingling */
  328.                     "%ldD",            /* depletion */
  329.                     shingling,
  330.                     depletion);
  331.  
  332.                 if(err != PDERR_NOERR)
  333.                     break;
  334.             }
  335.  
  336.             err = SendPrinterCommand(
  337.                 "\033&l0L"    /* perforation skip mode off */
  338.                 "\033*p0X"    /* set cursor to left edge */
  339.                 "\033*r0F"    /* raster image prints in orientation of logical page */
  340.                 "\033*t"
  341.                 "%ldR"        /* set raster graphics resolution */
  342.                 "\033*r"
  343.                 "%ldt"        /* set raster height */
  344.                 "%lds"        /* set raster width */
  345.                 "%ldu"        /* number of raster data components per line */
  346.                 "0A",        /* start raster graphics */
  347.                 PED->ped_XDotsInch,
  348.                 y,
  349.                 x,
  350.                 (num_components == 1) ? 1 : (-num_components));
  351.  
  352.             break;
  353.  
  354.         /* Scale, Dither and Render */
  355.         case 1:
  356.             /*    ct    - pointer to PrtInfo structure.
  357.              *    x    - 0.
  358.              *    y    - row # (0 to Height - 1).
  359.              */
  360.  
  361.             pi = (struct PrtInfo *)ct;
  362.  
  363.             /* Perform gamma correction on the colours. */
  364.             if(CONFIG_SUPPORTS_COLOR && gamma_table != NULL)
  365.             {
  366.                 CorrectColours(pi,gamma_table,colour_correction_buffer);
  367.                 colour_buffer = colour_correction_buffer;
  368.             }
  369.             else
  370.             {
  371.                 /* Use the uncorrected data. */
  372.                 colour_buffer = pi->pi_ColorInt;
  373.             }
  374.  
  375.             if(CONFIG_SUPPORTS_COLOR && PD->pd_Preferences.PrintShade == SHADE_COLOR)
  376.             {
  377.                 /* Transfer the pixels. */
  378.                 for(i = PCMYELLOW ; i <= PCMBLACK ; i++)
  379.                     Transfer(pi,colour_buffer,y,render_buffer[i],dither_data[i],i);
  380.  
  381.                 /* This is a CMYK printer, we don't need to mix
  382.                  * CMY to make black. This is why we clear the
  383.                  * CMY components if there are corresponding
  384.                  * black components for each pixel.
  385.                  */
  386.                 ClearColour(render_buffer,num_bytes_per_row);
  387.             }
  388.             else
  389.             {
  390.                 Transfer(pi,colour_buffer,y,render_buffer[PCMBLACK],dither_data[PCMBLACK],PCMBLACK);
  391.             }
  392.  
  393.             break;
  394.  
  395.         /* Dump Buffer to Printer */
  396.         case 2:
  397.             /*    ct    - 0.
  398.              *    x    - 0.
  399.              *    y    - # of rows sent (1 to NumRows).
  400.              */
  401.  
  402.             if(CONFIG_SUPPORTS_COLOR && PD->pd_Preferences.PrintShade == SHADE_COLOR)
  403.             {
  404.                 UBYTE * buffer = NULL;
  405.                 LONG size,method;
  406.  
  407.                 for(i = PCMBLACK ; i >= PCMYELLOW ; i--)
  408.                 {
  409.                     /* Strip all trailing white space. */
  410.                     size = StripWhiteSpace(render_buffer[i],num_bytes_per_row);
  411.                     if(size > 0)
  412.                     {
  413.                         LONG compressed_size;
  414.     
  415.                         /* Use the current output buffer. */
  416.                         buffer = print_buffers[current_print_buffer];
  417.                         current_print_buffer = (current_print_buffer + 1) % num_print_buffers;
  418.     
  419.                         /* Compress the raster data. */
  420.                         compressed_size = CompressMethod2(render_buffer[i],buffer,size);
  421.     
  422.                         /* Check for buffer overflow. */
  423.                         if(compressed_size < 0)
  424.                         {
  425.                             /* Compression did not result in space savings; reuse
  426.                              * the uncompressed data buffer.
  427.                              */
  428.                             memcpy(buffer,render_buffer[i],size);
  429.                             method = 0;
  430.                         }
  431.                         else
  432.                         {
  433.                             size = compressed_size;
  434.                             method = 2;
  435.                         }
  436.                     }
  437.                     else
  438.                     {
  439.                         /* No data to transfer, so we might as
  440.                          * well consider this "uncompressed"
  441.                          * raster data.
  442.                          */
  443.                         method = 0;
  444.                     }
  445.     
  446.                     /* Transfer raster data. */
  447.                     err = SendPrinterCommand("\033*b%ldm%ld%lc",method,size,(i == PCMYELLOW) ? 'W' : 'V');
  448.                     if(err == PDERR_NOERR && size > 0)
  449.                         err = (*PWrite)(buffer,size);
  450.  
  451.                     if(err != PDERR_NOERR)
  452.                         break;
  453.                 }
  454.             }
  455.             else
  456.             {
  457.                 UBYTE * buffer = NULL;
  458.                 LONG size,method;
  459.  
  460.                 /* Strip all trailing white space. */
  461.                 size = StripWhiteSpace(render_buffer[PCMBLACK],num_bytes_per_row);
  462.                 if(size > 0)
  463.                 {
  464.                     LONG compressed_size;
  465.         
  466.                     /* Use the current output buffer. */
  467.                     buffer = print_buffers[current_print_buffer];
  468.                     current_print_buffer = (current_print_buffer + 1) % num_print_buffers;
  469.         
  470.                     /* Compress the raster data. */
  471.                     compressed_size    = CompressMethod2(render_buffer[PCMBLACK],buffer,size);
  472.         
  473.                     /* Check for buffer overflow. */
  474.                     if(compressed_size < 0)
  475.                     {
  476.                         /* Compression did not result in space savings; reuse
  477.                          * the uncompressed data buffer.
  478.                          */
  479.                         memcpy(buffer,render_buffer[PCMBLACK],size);
  480.                         method = 0;
  481.                     }
  482.                     else
  483.                     {
  484.                         size = compressed_size;
  485.                         method = 2;
  486.                     }
  487.                 }
  488.                 else
  489.                 {
  490.                     /* No data to transfer, so we might as
  491.                      * well consider this "uncompressed"
  492.                      * raster data.
  493.                      */
  494.                     method = 0;
  495.                 }
  496.  
  497.                 /* Transfer raster data. */
  498.                 err = SendPrinterCommand("\033*b%ldm%ldW",method,size);
  499.                 if(err == PDERR_NOERR && size > 0)
  500.                     err = (*PWrite)(buffer,size);
  501.             }
  502.  
  503.             break;
  504.  
  505.         /* Clear and Init Buffer */
  506.         case 3:
  507.             /*    ct    - 0.
  508.              *    x    - 0.
  509.              *    y    - 0.
  510.              */
  511.             for(i = 0 ; i < NUM_ENTRIES(render_buffer) ; i++)
  512.             {
  513.                 if(render_buffer[i] != NULL)
  514.                     memset(render_buffer[i],0,num_bytes_per_row);
  515.             }
  516.  
  517.             break;
  518.  
  519.         /* Close Down */
  520.         case 4:
  521.             /*    ct    - error code.
  522.              *    x    - io_Special flag from IODRPReq struct
  523.              *    y    - 0.
  524.              */
  525.  
  526.             /* If user did not cancel the print... */
  527.             if (ct != PDERR_CANCEL)
  528.             {
  529.                 /* End raster graphics, perforation skip mode on */
  530.                 err = SendPrinterCommand("\033*rC\033&l1L");
  531.                 if (err == PDERR_NOERR)
  532.                 {
  533.                     /* If want to unload paper */
  534.                     if (!(x & SPECIAL_NOFORMFEED))
  535.                     {
  536.                         /* Eject paper */
  537.                         err = SendPrinterCommand("\014");
  538.                     }
  539.                 }
  540.             }
  541.  
  542.             /* Flag that there is no alpha data waiting that
  543.              * needs a formfeed (since we just did one).
  544.              */
  545.             PED->ped_PrintMode = 0;
  546.  
  547.             /* Wait for both buffers to empty. */
  548.             (*PBothReady)();
  549.  
  550.             /* Free the dithering and printing buffers. */
  551.             for(i = 0 ; i < NUM_ENTRIES(dither_data) ; i++)
  552.             {
  553.                 DeleteDitherData(dither_data[i]);
  554.                 dither_data[i] = NULL;
  555.             }
  556.  
  557.             for(i = 0 ; i < num_print_buffers ; i++)
  558.             {
  559.                 FreeVec(print_buffers[i]);
  560.                 print_buffers[i] = NULL;
  561.             }
  562.  
  563.             for(i = 0 ; i < NUM_ENTRIES(render_buffer) ; i++)
  564.             {
  565.                 FreeVec(render_buffer[i]);
  566.                 render_buffer[i] = NULL;
  567.             }
  568.  
  569.             FreeVec(colour_correction_buffer);
  570.             colour_correction_buffer = NULL;
  571.  
  572.             break;
  573.  
  574.         /* Pre-Master Initialization */
  575.         case 5:
  576.             /*    ct    - 0 or pointer to IODRPReq structure.
  577.              *    x    - io_Special flag from IODRPReq struct
  578.              *    y    - 0.
  579.              */
  580.  
  581.             /* Select density */
  582.             SetDensity(x & SPECIAL_DENSITYMASK);
  583.             break;
  584.     }
  585.  
  586.     return(err);
  587. }
  588.